﻿using System;
using System.Collections.Generic;
using System.Text;

#region Extension Methods for .NET 2

#if NET20

// you need this once (only), and it must be in this namespace
namespace System.Runtime.CompilerServices {
	[AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Class
	                                          | AttributeTargets.Method)]
	public sealed class ExtensionAttribute : Attribute {
	}
}

#endif

#if NET20 || NET35 || NET40

/// <summary>
/// To support progress reporting in .NET 3.5 and .NET 4.0
/// </summary>
public interface IProgress<T> {
	/// <summary>
	/// To support progress reporting in .NET 3.5 and .NET 4.0
	/// </summary>
	void Report(T value);
}

#endif

#endregion

#region LINQBridge - LINQ for .NET 2

#if NET20

// LINQBridge
// Atif Aziz, Joseph Albahari. All rights reserved.

namespace System.Linq {
	#region Imports

	using System;
	using Collections;
	using Collections.Generic;
	using Diagnostics;
	using LinqBridge;

	#endregion

	/// <summary>
	/// Provides a set of static (Shared in Visual Basic) methods for 
	/// querying objects that implement <see cref="IEnumerable{T}" />.
	/// </summary>
	internal static partial class Enumerable {
		/// <summary>
		/// Returns the input typed as <see cref="IEnumerable{T}"/>.
		/// </summary>
		public static IEnumerable<TSource> AsEnumerable<TSource>(this IEnumerable<TSource> source) {
			return source;
		}

		/// <summary>
		/// Returns an empty <see cref="IEnumerable{T}"/> that has the 
		/// specified type argument.
		/// </summary>
		public static IEnumerable<TResult> Empty<TResult>() {
			return Sequence<TResult>.Empty;
		}

		/// <summary>
		/// Converts the elements of an <see cref="IEnumerable"/> to the 
		/// specified type.
		/// </summary>
		public static IEnumerable<TResult> Cast<TResult>(
			this IEnumerable source) {
			if (source == null) {
				throw new ArgumentNullException("source");
			}

			return CastYield<TResult>(source);
		}

		private static IEnumerable<TResult> CastYield<TResult>(
			IEnumerable source) {
			foreach (var item in source) {
				yield return (TResult) item;
			}
		}

		/// <summary>
		/// Filters the elements of an <see cref="IEnumerable"/> based on a specified type.
		/// </summary>
		public static IEnumerable<TResult> OfType<TResult>(
			this IEnumerable source) {
			if (source == null) {
				throw new ArgumentNullException("source");
			}

			return OfTypeYield<TResult>(source);
		}

		private static IEnumerable<TResult> OfTypeYield<TResult>(
			IEnumerable source) {
			foreach (var item in source) {
				if (item is TResult) {
					yield return (TResult) item;
				}
			}
		}

		/// <summary>
		/// Generates a sequence of integral numbers within a specified range.
		/// </summary>
		/// <param name="start">The value of the first integer in the sequence.</param>
		/// <param name="count">The number of sequential integers to generate.</param>
		public static IEnumerable<int> Range(int start, int count) {
			if (count < 0) {
				throw new ArgumentOutOfRangeException("count", count, null);
			}

			var end = (long) start + count;
			if (end - 1 >= int.MaxValue) {
				throw new ArgumentOutOfRangeException("count", count, null);
			}

			return RangeYield(start, end);
		}

		private static IEnumerable<int> RangeYield(int start, long end) {
			for (var i = start; i < end; i++) {
				yield return i;
			}
		}

		/// <summary>
		/// Generates a sequence that contains one repeated value.
		/// </summary>
		public static IEnumerable<TResult> Repeat<TResult>(TResult element, int count) {
			if (count < 0) {
				throw new ArgumentOutOfRangeException("count", count, null);
			}

			return RepeatYield(element, count);
		}

		private static IEnumerable<TResult> RepeatYield<TResult>(TResult element, int count) {
			for (var i = 0; i < count; i++) {
				yield return element;
			}
		}

		/// <summary>
		/// Filters a sequence of values based on a predicate.
		/// </summary>
		public static IEnumerable<TSource> Where<TSource>(
			this IEnumerable<TSource> source,
			Func<TSource, bool> predicate) {
			if (predicate == null) {
				throw new ArgumentNullException("predicate");
			}

			return source.Where((item, i) => predicate(item));
		}

		/// <summary>
		/// Filters a sequence of values based on a predicate. 
		/// Each element's index is used in the logic of the predicate function.
		/// </summary>
		public static IEnumerable<TSource> Where<TSource>(
			this IEnumerable<TSource> source,
			Func<TSource, int, bool> predicate) {
			if (source == null) {
				throw new ArgumentNullException("source");
			}

			if (predicate == null) {
				throw new ArgumentNullException("predicate");
			}

			return WhereYield(source, predicate);
		}

		private static IEnumerable<TSource> WhereYield<TSource>(
			IEnumerable<TSource> source,
			Func<TSource, int, bool> predicate) {
			var i = 0;
			foreach (var item in source) {
				if (predicate(item, i++)) {
					yield return item;
				}
			}
		}

		/// <summary>
		/// Projects each element of a sequence into a new form.
		/// </summary>
		public static IEnumerable<TResult> Select<TSource, TResult>(
			this IEnumerable<TSource> source,
			Func<TSource, TResult> selector) {
			if (selector == null) {
				throw new ArgumentNullException("selector");
			}

			return source.Select((item, i) => selector(item));
		}

		/// <summary>
		/// Projects each element of a sequence into a new form by 
		/// incorporating the element's index.
		/// </summary>
		public static IEnumerable<TResult> Select<TSource, TResult>(
			this IEnumerable<TSource> source,
			Func<TSource, int, TResult> selector) {
			if (source == null) {
				throw new ArgumentNullException("source");
			}

			if (selector == null) {
				throw new ArgumentNullException("selector");
			}

			return SelectYield(source, selector);
		}

		private static IEnumerable<TResult> SelectYield<TSource, TResult>(
			IEnumerable<TSource> source,
			Func<TSource, int, TResult> selector) {
			var i = 0;
			foreach (var item in source) {
				yield return selector(item, i++);
			}
		}

		/// <summary>
		/// Projects each element of a sequence to an <see cref="IEnumerable{T}" /> 
		/// and flattens the resulting sequences into one sequence.
		/// </summary>
		public static IEnumerable<TResult> SelectMany<TSource, TResult>(
			this IEnumerable<TSource> source,
			Func<TSource, IEnumerable<TResult>> selector) {
			if (selector == null) {
				throw new ArgumentNullException("selector");
			}

			return source.SelectMany((item, i) => selector(item));
		}

		/// <summary>
		/// Projects each element of a sequence to an <see cref="IEnumerable{T}" />, 
		/// and flattens the resulting sequences into one sequence. The 
		/// index of each source element is used in the projected form of 
		/// that element.
		/// </summary>
		public static IEnumerable<TResult> SelectMany<TSource, TResult>(
			this IEnumerable<TSource> source,
			Func<TSource, int, IEnumerable<TResult>> selector) {
			if (selector == null) {
				throw new ArgumentNullException("selector");
			}

			return source.SelectMany(selector, (item, subitem) => subitem);
		}

		/// <summary>
		/// Projects each element of a sequence to an <see cref="IEnumerable{T}" />, 
		/// flattens the resulting sequences into one sequence, and invokes 
		/// a result selector function on each element therein.
		/// </summary>
		public static IEnumerable<TResult> SelectMany<TSource, TCollection, TResult>(
			this IEnumerable<TSource> source,
			Func<TSource, IEnumerable<TCollection>> collectionSelector,
			Func<TSource, TCollection, TResult> resultSelector) {
			if (collectionSelector == null) {
				throw new ArgumentNullException("collectionSelector");
			}

			return source.SelectMany((item, i) => collectionSelector(item), resultSelector);
		}

		/// <summary>
		/// Projects each element of a sequence to an <see cref="IEnumerable{T}" />, 
		/// flattens the resulting sequences into one sequence, and invokes 
		/// a result selector function on each element therein. The index of 
		/// each source element is used in the intermediate projected form 
		/// of that element.
		/// </summary>
		public static IEnumerable<TResult> SelectMany<TSource, TCollection, TResult>(
			this IEnumerable<TSource> source,
			Func<TSource, int, IEnumerable<TCollection>> collectionSelector,
			Func<TSource, TCollection, TResult> resultSelector) {
			if (source == null) {
				throw new ArgumentNullException("source");
			}

			if (collectionSelector == null) {
				throw new ArgumentNullException("collectionSelector");
			}

			if (resultSelector == null) {
				throw new ArgumentNullException("resultSelector");
			}

			return SelectManyYield(source, collectionSelector, resultSelector);
		}

		private static IEnumerable<TResult> SelectManyYield<TSource, TCollection, TResult>(
			this IEnumerable<TSource> source,
			Func<TSource, int, IEnumerable<TCollection>> collectionSelector,
			Func<TSource, TCollection, TResult> resultSelector) {
			var i = 0;
			foreach (var item in source)
			foreach (var subitem in collectionSelector(item, i++)) {
				yield return resultSelector(item, subitem);
			}
		}

		/// <summary>
		/// Returns elements from a sequence as long as a specified condition is true.
		/// </summary>
		public static IEnumerable<TSource> TakeWhile<TSource>(
			this IEnumerable<TSource> source,
			Func<TSource, bool> predicate) {
			if (predicate == null) {
				throw new ArgumentNullException("predicate");
			}

			return source.TakeWhile((item, i) => predicate(item));
		}

		/// <summary>
		/// Returns elements from a sequence as long as a specified condition is true.
		/// The element's index is used in the logic of the predicate function.
		/// </summary>
		public static IEnumerable<TSource> TakeWhile<TSource>(
			this IEnumerable<TSource> source,
			Func<TSource, int, bool> predicate) {
			if (source == null) {
				throw new ArgumentNullException("source");
			}

			if (predicate == null) {
				throw new ArgumentNullException("predicate");
			}

			return TakeWhileYield(source, predicate);
		}

		private static IEnumerable<TSource> TakeWhileYield<TSource>(
			this IEnumerable<TSource> source,
			Func<TSource, int, bool> predicate) {
			var i = 0;
			foreach (var item in source) {
				if (predicate(item, i++)) {
					yield return item;
				}
				else {
					break;
				}
			}
		}

		/// <summary>
		/// Returns a specified number of contiguous elements from the start 
		/// of a sequence.
		/// </summary>
		public static IEnumerable<TSource> Take<TSource>(
			this IEnumerable<TSource> source,
			int count) {
			return source.TakeWhile((item, i) => i < count);
		}

		private static class Futures<T> {
			public static readonly Func<T> Default = () => default(T);
			public static readonly Func<T> Undefined = () => { throw new InvalidOperationException(); };
		}

		/// <summary>
		/// Base implementation of First operator.
		/// </summary>
		private static TSource FirstImpl<TSource>(
			this IEnumerable<TSource> source,
			Func<TSource> empty) {
			if (source == null) {
				throw new ArgumentNullException("source");
			}

			Debug.Assert(empty != null);

			var list = source as IList<TSource>; // optimized case for lists
			if (list != null) {
				return list.Count > 0 ? list[0] : empty();
			}

			using (var e = source.GetEnumerator()) // fallback for enumeration
			{
				return e.MoveNext() ? e.Current : empty();
			}
		}

		/// <summary>
		/// Returns the first element of a sequence.
		/// </summary>
		public static TSource First<TSource>(
			this IEnumerable<TSource> source) {
			return source.FirstImpl(Futures<TSource>.Undefined);
		}

		/// <summary>
		/// Returns the first element in a sequence that satisfies a specified condition.
		/// </summary>
		public static TSource First<TSource>(
			this IEnumerable<TSource> source,
			Func<TSource, bool> predicate) {
			return First(source.Where(predicate));
		}

		/// <summary>
		/// Returns the first element of a sequence, or a default value if 
		/// the sequence contains no elements.
		/// </summary>
		public static TSource FirstOrDefault<TSource>(
			this IEnumerable<TSource> source) {
			return source.FirstImpl(Futures<TSource>.Default);
		}

		/// <summary>
		/// Returns the first element of the sequence that satisfies a 
		/// condition or a default value if no such element is found.
		/// </summary>
		public static TSource FirstOrDefault<TSource>(
			this IEnumerable<TSource> source,
			Func<TSource, bool> predicate) {
			return FirstOrDefault(source.Where(predicate));
		}

		/// <summary>
		/// Base implementation of Last operator.
		/// </summary>
		private static TSource LastImpl<TSource>(
			this IEnumerable<TSource> source,
			Func<TSource> empty) {
			if (source == null) {
				throw new ArgumentNullException("source");
			}

			var list = source as IList<TSource>; // optimized case for lists
			if (list != null) {
				return list.Count > 0 ? list[list.Count - 1] : empty();
			}

			using (var e = source.GetEnumerator()) {
				if (!e.MoveNext()) {
					return empty();
				}

				var last = e.Current;
				while (e.MoveNext()) {
					last = e.Current;
				}

				return last;
			}
		}

		/// <summary>
		/// Returns the last element of a sequence.
		/// </summary>
		public static TSource Last<TSource>(
			this IEnumerable<TSource> source) {
			return source.LastImpl(Futures<TSource>.Undefined);
		}

		/// <summary>
		/// Returns the last element of a sequence that satisfies a 
		/// specified condition.
		/// </summary>
		public static TSource Last<TSource>(
			this IEnumerable<TSource> source,
			Func<TSource, bool> predicate) {
			return Last(source.Where(predicate));
		}

		/// <summary>
		/// Returns the last element of a sequence, or a default value if 
		/// the sequence contains no elements.
		/// </summary>
		public static TSource LastOrDefault<TSource>(
			this IEnumerable<TSource> source) {
			return source.LastImpl(Futures<TSource>.Default);
		}

		/// <summary>
		/// Returns the last element of a sequence that satisfies a 
		/// condition or a default value if no such element is found.
		/// </summary>
		public static TSource LastOrDefault<TSource>(
			this IEnumerable<TSource> source,
			Func<TSource, bool> predicate) {
			return LastOrDefault(source.Where(predicate));
		}

		/// <summary>
		/// Base implementation of Single operator.
		/// </summary>
		private static TSource SingleImpl<TSource>(
			this IEnumerable<TSource> source,
			Func<TSource> empty) {
			if (source == null) {
				throw new ArgumentNullException("source");
			}

			using (var e = source.GetEnumerator()) {
				if (e.MoveNext()) {
					var single = e.Current;
					if (!e.MoveNext()) {
						return single;
					}

					throw new InvalidOperationException();
				}

				return empty();
			}
		}

		/// <summary>
		/// Returns the only element of a sequence, and throws an exception 
		/// if there is not exactly one element in the sequence.
		/// </summary>
		public static TSource Single<TSource>(
			this IEnumerable<TSource> source) {
			return source.SingleImpl(Futures<TSource>.Undefined);
		}

		/// <summary>
		/// Returns the only element of a sequence that satisfies a 
		/// specified condition, and throws an exception if more than one 
		/// such element exists.
		/// </summary>
		public static TSource Single<TSource>(
			this IEnumerable<TSource> source,
			Func<TSource, bool> predicate) {
			return Single(source.Where(predicate));
		}

		/// <summary>
		/// Returns the only element of a sequence, or a default value if 
		/// the sequence is empty; this method throws an exception if there 
		/// is more than one element in the sequence.
		/// </summary>
		public static TSource SingleOrDefault<TSource>(
			this IEnumerable<TSource> source) {
			return source.SingleImpl(Futures<TSource>.Default);
		}

		/// <summary>
		/// Returns the only element of a sequence that satisfies a 
		/// specified condition or a default value if no such element 
		/// exists; this method throws an exception if more than one element 
		/// satisfies the condition.
		/// </summary>
		public static TSource SingleOrDefault<TSource>(
			this IEnumerable<TSource> source,
			Func<TSource, bool> predicate) {
			return SingleOrDefault(source.Where(predicate));
		}

		/// <summary>
		/// Returns the element at a specified index in a sequence.
		/// </summary>
		public static TSource ElementAt<TSource>(
			this IEnumerable<TSource> source,
			int index) {
			if (source == null) {
				throw new ArgumentNullException("source");
			}

			if (index < 0) {
				throw new ArgumentOutOfRangeException("index", index, null);
			}

			var list = source as IList<TSource>;
			if (list != null) {
				return list[index];
			}

			try {
				return source.SkipWhile((item, i) => i < index).First();
			}
			catch (InvalidOperationException) // if thrown by First
			{
				throw new ArgumentOutOfRangeException("index", index, null);
			}
		}

		/// <summary>
		/// Returns the element at a specified index in a sequence or a 
		/// default value if the index is out of range.
		/// </summary>
		public static TSource ElementAtOrDefault<TSource>(
			this IEnumerable<TSource> source,
			int index) {
			if (source == null) {
				throw new ArgumentNullException("source");
			}

			if (index < 0) {
				return default(TSource);
			}

			var list = source as IList<TSource>;
			if (list != null) {
				return index < list.Count ? list[index] : default(TSource);
			}

			return source.SkipWhile((item, i) => i < index).FirstOrDefault();
		}

		/// <summary>
		/// Inverts the order of the elements in a sequence.
		/// </summary>
		public static IEnumerable<TSource> Reverse<TSource>(
			this IEnumerable<TSource> source) {
			if (source == null) {
				throw new ArgumentNullException("source");
			}

			return ReverseYield(source);
		}

		private static IEnumerable<TSource> ReverseYield<TSource>(IEnumerable<TSource> source) {
			var stack = new Stack<TSource>();
			foreach (var item in source) {
				stack.Push(item);
			}

			foreach (var item in stack) {
				yield return item;
			}
		}

		/// <summary>
		/// Bypasses elements in a sequence as long as a specified condition 
		/// is true and then returns the remaining elements.
		/// </summary>
		public static IEnumerable<TSource> SkipWhile<TSource>(
			this IEnumerable<TSource> source,
			Func<TSource, bool> predicate) {
			if (predicate == null) {
				throw new ArgumentNullException("predicate");
			}

			return source.SkipWhile((item, i) => predicate(item));
		}

		/// <summary>
		/// Bypasses elements in a sequence as long as a specified condition 
		/// is true and then returns the remaining elements. The element's 
		/// index is used in the logic of the predicate function.
		/// </summary>
		public static IEnumerable<TSource> SkipWhile<TSource>(
			this IEnumerable<TSource> source,
			Func<TSource, int, bool> predicate) {
			if (source == null) {
				throw new ArgumentNullException("source");
			}

			if (predicate == null) {
				throw new ArgumentNullException("predicate");
			}

			return SkipWhileYield(source, predicate);
		}

		private static IEnumerable<TSource> SkipWhileYield<TSource>(
			IEnumerable<TSource> source,
			Func<TSource, int, bool> predicate) {
			using (var e = source.GetEnumerator()) {
				for (var i = 0;; i++) {
					if (!e.MoveNext()) {
						yield break;
					}

					if (!predicate(e.Current, i)) {
						break;
					}
				}

				do {
					yield return e.Current;
				} while (e.MoveNext());
			}
		}

		/// <summary>
		/// Bypasses a specified number of elements in a sequence and then 
		/// returns the remaining elements.
		/// </summary>
		public static IEnumerable<TSource> Skip<TSource>(
			this IEnumerable<TSource> source,
			int count) {
			return source.SkipWhile((item, i) => i < count);
		}

		/// <summary>
		/// Returns the number of elements in a sequence.
		/// </summary>
		public static int Count<TSource>(
			this IEnumerable<TSource> source) {
			if (source == null) {
				throw new ArgumentNullException("source");
			}

			var collection = source as ICollection;
			return collection != null
				? collection.Count
				: source.Aggregate(0, (count, item) => checked(count + 1));
		}

		/// <summary>
		/// Returns a number that represents how many elements in the 
		/// specified sequence satisfy a condition.
		/// </summary>
		public static int Count<TSource>(
			this IEnumerable<TSource> source,
			Func<TSource, bool> predicate) {
			return Count(source.Where(predicate));
		}

		/// <summary>
		/// Returns an <see cref="Int64"/> that represents the total number 
		/// of elements in a sequence.
		/// </summary>
		public static long LongCount<TSource>(
			this IEnumerable<TSource> source) {
			if (source == null) {
				throw new ArgumentNullException("source");
			}

			var array = source as Array;
			return array != null
				? array.LongLength
				: source.Aggregate(0L, (count, item) => count + 1);
		}

		/// <summary>
		/// Returns an <see cref="Int64"/> that represents how many elements 
		/// in a sequence satisfy a condition.
		/// </summary>
		public static long LongCount<TSource>(
			this IEnumerable<TSource> source,
			Func<TSource, bool> predicate) {
			return LongCount(source.Where(predicate));
		}

		/// <summary>
		/// Concatenates two sequences.
		/// </summary>
		public static IEnumerable<TSource> Concat<TSource>(
			this IEnumerable<TSource> first,
			IEnumerable<TSource> second) {
			if (first == null) {
				throw new ArgumentNullException("first");
			}

			if (second == null) {
				throw new ArgumentNullException("second");
			}

			return ConcatYield(first, second);
		}

		private static IEnumerable<TSource> ConcatYield<TSource>(
			IEnumerable<TSource> first,
			IEnumerable<TSource> second) {
			foreach (var item in first) {
				yield return item;
			}

			foreach (var item in second) {
				yield return item;
			}
		}

		/// <summary>
		/// Creates a <see cref="List{T}"/> from an <see cref="IEnumerable{T}"/>.
		/// </summary>
		public static List<TSource> ToList<TSource>(
			this IEnumerable<TSource> source) {
			if (source == null) {
				throw new ArgumentNullException("source");
			}

			return new List<TSource>(source);
		}

		/// <summary>
		/// Creates an array from an <see cref="IEnumerable{T}"/>.
		/// </summary>
		public static TSource[] ToArray<TSource>(
			this IEnumerable<TSource> source) {
			return source.ToList().ToArray();
		}

		/// <summary>
		/// Returns distinct elements from a sequence by using the default 
		/// equality comparer to compare values.
		/// </summary>
		public static IEnumerable<TSource> Distinct<TSource>(
			this IEnumerable<TSource> source) {
			return Distinct(source, /* comparer */ null);
		}

		/// <summary>
		/// Returns distinct elements from a sequence by using a specified 
		/// <see cref="IEqualityComparer{T}"/> to compare values.
		/// </summary>
		public static IEnumerable<TSource> Distinct<TSource>(
			this IEnumerable<TSource> source,
			IEqualityComparer<TSource> comparer) {
			if (source == null) {
				throw new ArgumentNullException("source");
			}

			return DistinctYield(source, comparer);
		}

		private static IEnumerable<TSource> DistinctYield<TSource>(
			IEnumerable<TSource> source,
			IEqualityComparer<TSource> comparer) {
			var set = new Dictionary<TSource, object>(comparer);
			var gotNull = false;

			foreach (var item in source) {
				if (item == null) {
					if (gotNull) {
						continue;
					}

					gotNull = true;
				}
				else {
					if (set.ContainsKey(item)) {
						continue;
					}

					set.Add(item, null);
				}

				yield return item;
			}
		}

		/// <summary>
		/// Creates a <see cref="Lookup{TKey,TElement}" /> from an 
		/// <see cref="IEnumerable{T}" /> according to a specified key 
		/// selector function.
		/// </summary>
		public static ILookup<TKey, TSource> ToLookup<TSource, TKey>(
			this IEnumerable<TSource> source,
			Func<TSource, TKey> keySelector) {
			return ToLookup(source, keySelector, e => e, /* comparer */ null);
		}

		/// <summary>
		/// Creates a <see cref="Lookup{TKey,TElement}" /> from an 
		/// <see cref="IEnumerable{T}" /> according to a specified key 
		/// selector function and a key comparer.
		/// </summary>
		public static ILookup<TKey, TSource> ToLookup<TSource, TKey>(
			this IEnumerable<TSource> source,
			Func<TSource, TKey> keySelector,
			IEqualityComparer<TKey> comparer) {
			return ToLookup(source, keySelector, e => e, comparer);
		}

		/// <summary>
		/// Creates a <see cref="Lookup{TKey,TElement}" /> from an 
		/// <see cref="IEnumerable{T}" /> according to specified key 
		/// and element selector functions.
		/// </summary>
		public static ILookup<TKey, TElement> ToLookup<TSource, TKey, TElement>(
			this IEnumerable<TSource> source,
			Func<TSource, TKey> keySelector,
			Func<TSource, TElement> elementSelector) {
			return ToLookup(source, keySelector, elementSelector, /* comparer */ null);
		}

		/// <summary>
		/// Creates a <see cref="Lookup{TKey,TElement}" /> from an 
		/// <see cref="IEnumerable{T}" /> according to a specified key 
		/// selector function, a comparer and an element selector function.
		/// </summary>
		public static ILookup<TKey, TElement> ToLookup<TSource, TKey, TElement>(
			this IEnumerable<TSource> source,
			Func<TSource, TKey> keySelector,
			Func<TSource, TElement> elementSelector,
			IEqualityComparer<TKey> comparer) {
			if (source == null) {
				throw new ArgumentNullException("source");
			}

			if (keySelector == null) {
				throw new ArgumentNullException("keySelector");
			}

			if (elementSelector == null) {
				throw new ArgumentNullException("elementSelector");
			}

			var lookup = new Lookup<TKey, TElement>(comparer);

			foreach (var item in source) {
				var key = keySelector(item);

				var grouping = (Grouping<TKey, TElement>) lookup.Find(key);
				if (grouping == null) {
					grouping = new Grouping<TKey, TElement>(key);
					lookup.Add(grouping);
				}

				grouping.Add(elementSelector(item));
			}

			return lookup;
		}

		/// <summary>
		/// Groups the elements of a sequence according to a specified key 
		/// selector function.
		/// </summary>
		public static IEnumerable<IGrouping<TKey, TSource>> GroupBy<TSource, TKey>(
			this IEnumerable<TSource> source,
			Func<TSource, TKey> keySelector) {
			return GroupBy(source, keySelector, /* comparer */ null);
		}

		/// <summary>
		/// Groups the elements of a sequence according to a specified key 
		/// selector function and compares the keys by using a specified 
		/// comparer.
		/// </summary>
		public static IEnumerable<IGrouping<TKey, TSource>> GroupBy<TSource, TKey>(
			this IEnumerable<TSource> source,
			Func<TSource, TKey> keySelector,
			IEqualityComparer<TKey> comparer) {
			return GroupBy(source, keySelector, e => e, comparer);
		}

		/// <summary>
		/// Groups the elements of a sequence according to a specified key 
		/// selector function and projects the elements for each group by 
		/// using a specified function.
		/// </summary>
		public static IEnumerable<IGrouping<TKey, TElement>> GroupBy<TSource, TKey, TElement>(
			this IEnumerable<TSource> source,
			Func<TSource, TKey> keySelector,
			Func<TSource, TElement> elementSelector) {
			return GroupBy(source, keySelector, elementSelector, /* comparer */ null);
		}

		/// <summary>
		/// Groups the elements of a sequence according to a specified key 
		/// selector function and creates a result value from each group and 
		/// its key.
		/// </summary>
		public static IEnumerable<IGrouping<TKey, TElement>> GroupBy<TSource, TKey, TElement>(
			this IEnumerable<TSource> source,
			Func<TSource, TKey> keySelector,
			Func<TSource, TElement> elementSelector,
			IEqualityComparer<TKey> comparer) {
			if (source == null) {
				throw new ArgumentNullException("source");
			}

			if (keySelector == null) {
				throw new ArgumentNullException("keySelector");
			}

			if (elementSelector == null) {
				throw new ArgumentNullException("elementSelector");
			}

			return ToLookup(source, keySelector, elementSelector, comparer);
		}

		/// <summary>
		/// Groups the elements of a sequence according to a key selector 
		/// function. The keys are compared by using a comparer and each 
		/// group's elements are projected by using a specified function.
		/// </summary>
		public static IEnumerable<TResult> GroupBy<TSource, TKey, TResult>(
			this IEnumerable<TSource> source,
			Func<TSource, TKey> keySelector,
			Func<TKey, IEnumerable<TSource>, TResult> resultSelector) {
			return GroupBy(source, keySelector, resultSelector, /* comparer */ null);
		}

		/// <summary>
		/// Groups the elements of a sequence according to a specified key 
		/// selector function and creates a result value from each group and 
		/// its key. The elements of each group are projected by using a 
		/// specified function.
		/// </summary>
		public static IEnumerable<TResult> GroupBy<TSource, TKey, TResult>(
			this IEnumerable<TSource> source,
			Func<TSource, TKey> keySelector,
			Func<TKey, IEnumerable<TSource>, TResult> resultSelector,
			IEqualityComparer<TKey> comparer) {
			if (source == null) {
				throw new ArgumentNullException("source");
			}

			if (keySelector == null) {
				throw new ArgumentNullException("keySelector");
			}

			if (resultSelector == null) {
				throw new ArgumentNullException("resultSelector");
			}

			return ToLookup(source, keySelector, comparer).Select(g => resultSelector(g.Key, g));
		}

		/// <summary>
		/// Groups the elements of a sequence according to a specified key 
		/// selector function and creates a result value from each group and 
		/// its key. The keys are compared by using a specified comparer.
		/// </summary>
		public static IEnumerable<TResult> GroupBy<TSource, TKey, TElement, TResult>(
			this IEnumerable<TSource> source,
			Func<TSource, TKey> keySelector,
			Func<TSource, TElement> elementSelector,
			Func<TKey, IEnumerable<TElement>, TResult> resultSelector) {
			return GroupBy(source, keySelector, elementSelector, resultSelector, /* comparer */ null);
		}

		/// <summary>
		/// Groups the elements of a sequence according to a specified key 
		/// selector function and creates a result value from each group and 
		/// its key. Key values are compared by using a specified comparer, 
		/// and the elements of each group are projected by using a 
		/// specified function.
		/// </summary>
		public static IEnumerable<TResult> GroupBy<TSource, TKey, TElement, TResult>(
			this IEnumerable<TSource> source,
			Func<TSource, TKey> keySelector,
			Func<TSource, TElement> elementSelector,
			Func<TKey, IEnumerable<TElement>, TResult> resultSelector,
			IEqualityComparer<TKey> comparer) {
			if (source == null) {
				throw new ArgumentNullException("source");
			}

			if (keySelector == null) {
				throw new ArgumentNullException("keySelector");
			}

			if (elementSelector == null) {
				throw new ArgumentNullException("elementSelector");
			}

			if (resultSelector == null) {
				throw new ArgumentNullException("resultSelector");
			}

			return ToLookup(source, keySelector, elementSelector, comparer)
				.Select(g => resultSelector(g.Key, g));
		}

		/// <summary>
		/// Applies an accumulator function over a sequence.
		/// </summary>
		public static TSource Aggregate<TSource>(
			this IEnumerable<TSource> source,
			Func<TSource, TSource, TSource> func) {
			if (source == null) {
				throw new ArgumentNullException("source");
			}

			if (func == null) {
				throw new ArgumentNullException("func");
			}

			using (var e = source.GetEnumerator()) {
				if (!e.MoveNext()) {
					throw new InvalidOperationException();
				}

				return e.Renumerable().Skip(1).Aggregate(e.Current, func);
			}
		}

		/// <summary>
		/// Applies an accumulator function over a sequence. The specified 
		/// seed value is used as the initial accumulator value.
		/// </summary>
		public static TAccumulate Aggregate<TSource, TAccumulate>(
			this IEnumerable<TSource> source,
			TAccumulate seed,
			Func<TAccumulate, TSource, TAccumulate> func) {
			return Aggregate(source, seed, func, r => r);
		}

		/// <summary>
		/// Applies an accumulator function over a sequence. The specified 
		/// seed value is used as the initial accumulator value, and the 
		/// specified function is used to select the result value.
		/// </summary>
		public static TResult Aggregate<TSource, TAccumulate, TResult>(
			this IEnumerable<TSource> source,
			TAccumulate seed,
			Func<TAccumulate, TSource, TAccumulate> func,
			Func<TAccumulate, TResult> resultSelector) {
			if (source == null) {
				throw new ArgumentNullException("source");
			}

			if (func == null) {
				throw new ArgumentNullException("func");
			}

			if (resultSelector == null) {
				throw new ArgumentNullException("resultSelector");
			}

			var result = seed;

			foreach (var item in source) {
				result = func(result, item);
			}

			return resultSelector(result);
		}

		/// <summary>
		/// Produces the set union of two sequences by using the default 
		/// equality comparer.
		/// </summary>
		public static IEnumerable<TSource> Union<TSource>(
			this IEnumerable<TSource> first,
			IEnumerable<TSource> second) {
			return Union(first, second, /* comparer */ null);
		}

		/// <summary>
		/// Produces the set union of two sequences by using a specified 
		/// <see cref="IEqualityComparer{T}" />.
		/// </summary>
		public static IEnumerable<TSource> Union<TSource>(
			this IEnumerable<TSource> first,
			IEnumerable<TSource> second,
			IEqualityComparer<TSource> comparer) {
			return first.Concat(second).Distinct(comparer);
		}

		/// <summary>
		/// Returns the elements of the specified sequence or the type 
		/// parameter's default value in a singleton collection if the 
		/// sequence is empty.
		/// </summary>
		public static IEnumerable<TSource> DefaultIfEmpty<TSource>(
			this IEnumerable<TSource> source) {
			return source.DefaultIfEmpty(default(TSource));
		}

		/// <summary>
		/// Returns the elements of the specified sequence or the specified 
		/// value in a singleton collection if the sequence is empty.
		/// </summary>
		public static IEnumerable<TSource> DefaultIfEmpty<TSource>(
			this IEnumerable<TSource> source,
			TSource defaultValue) {
			if (source == null) {
				throw new ArgumentNullException("source");
			}

			return DefaultIfEmptyYield(source, defaultValue);
		}

		private static IEnumerable<TSource> DefaultIfEmptyYield<TSource>(
			IEnumerable<TSource> source,
			TSource defaultValue) {
			using (var e = source.GetEnumerator()) {
				if (!e.MoveNext()) {
					yield return defaultValue;
				}
				else {
					do {
						yield return e.Current;
					} while (e.MoveNext());
				}
			}
		}

		/// <summary>
		/// Determines whether all elements of a sequence satisfy a condition.
		/// </summary>
		public static bool All<TSource>(
			this IEnumerable<TSource> source,
			Func<TSource, bool> predicate) {
			if (source == null) {
				throw new ArgumentNullException("source");
			}

			if (predicate == null) {
				throw new ArgumentNullException("predicate");
			}

			foreach (var item in source) {
				if (!predicate(item)) {
					return false;
				}
			}

			return true;
		}

		/// <summary>
		/// Determines whether a sequence contains any elements.
		/// </summary>
		public static bool Any<TSource>(
			this IEnumerable<TSource> source) {
			if (source == null) {
				throw new ArgumentNullException("source");
			}

			using (var e = source.GetEnumerator()) {
				return e.MoveNext();
			}
		}

		/// <summary>
		/// Determines whether any element of a sequence satisfies a 
		/// condition.
		/// </summary>
		public static bool Any<TSource>(
			this IEnumerable<TSource> source,
			Func<TSource, bool> predicate) {
			return source.Where(predicate).Any();
		}

		/// <summary>
		/// Determines whether a sequence contains a specified element by 
		/// using the default equality comparer.
		/// </summary>
		public static bool Contains<TSource>(
			this IEnumerable<TSource> source,
			TSource value) {
			return source.Contains(value, /* comparer */ null);
		}

		/// <summary>
		/// Determines whether a sequence contains a specified element by 
		/// using a specified <see cref="IEqualityComparer{T}" />.
		/// </summary>
		public static bool Contains<TSource>(
			this IEnumerable<TSource> source,
			TSource value,
			IEqualityComparer<TSource> comparer) {
			if (source == null) {
				throw new ArgumentNullException("source");
			}

			if (comparer == null) {
				var collection = source as ICollection<TSource>;
				if (collection != null) {
					return collection.Contains(value);
				}
			}

			comparer = comparer ?? EqualityComparer<TSource>.Default;
			return source.Any(item => comparer.Equals(item, value));
		}

		/// <summary>
		/// Determines whether two sequences are equal by comparing the 
		/// elements by using the default equality comparer for their type.
		/// </summary>
		public static bool SequenceEqual<TSource>(
			this IEnumerable<TSource> first,
			IEnumerable<TSource> second) {
			return first.SequenceEqual(second, /* comparer */ null);
		}

		/// <summary>
		/// Determines whether two sequences are equal by comparing their 
		/// elements by using a specified <see cref="IEqualityComparer{T}" />.
		/// </summary>
		public static bool SequenceEqual<TSource>(
			this IEnumerable<TSource> first,
			IEnumerable<TSource> second,
			IEqualityComparer<TSource> comparer) {
			if (first == null) {
				throw new ArgumentNullException("frist");
			}

			if (second == null) {
				throw new ArgumentNullException("second");
			}

			comparer = comparer ?? EqualityComparer<TSource>.Default;

			using (IEnumerator<TSource> lhs = first.GetEnumerator(),
				rhs = second.GetEnumerator()) {
				do {
					if (!lhs.MoveNext()) {
						return !rhs.MoveNext();
					}

					if (!rhs.MoveNext()) {
						return false;
					}
				} while (comparer.Equals(lhs.Current, rhs.Current));
			}

			return false;
		}

		/// <summary>
		/// Base implementation for Min/Max operator.
		/// </summary>
		private static TSource MinMaxImpl<TSource>(
			this IEnumerable<TSource> source,
			Func<TSource, TSource, bool> lesser) {
			if (source == null) {
				throw new ArgumentNullException("source");
			}

			Debug.Assert(lesser != null);

			if (typeof(TSource).IsClass) // ReSharper disable CompareNonConstrainedGenericWithNull                
			{
				source = source.Where(e => e != null).DefaultIfEmpty(); // ReSharper restore CompareNonConstrainedGenericWithNull
			}

			return source.Aggregate((a, item) => lesser(a, item) ? a : item);
		}

		/// <summary>
		/// Base implementation for Min/Max operator for nullable types.
		/// </summary>
		private static TSource? MinMaxImpl<TSource>(
			this IEnumerable<TSource?> source,
			TSource? seed, Func<TSource?, TSource?, bool> lesser) where TSource : struct {
			if (source == null) {
				throw new ArgumentNullException("source");
			}

			Debug.Assert(lesser != null);

			return source.Aggregate(seed, (a, item) => lesser(a, item) ? a : item);

			//  == MinMaxImpl(Repeat<TSource?>(null, 1).Concat(source), lesser);
		}

		/// <summary>
		/// Returns the minimum value in a generic sequence.
		/// </summary>
		public static TSource Min<TSource>(
			this IEnumerable<TSource> source) {
			var comparer = Comparer<TSource>.Default;
			return source.MinMaxImpl((x, y) => comparer.Compare(x, y) < 0);
		}

		/// <summary>
		/// Invokes a transform function on each element of a generic 
		/// sequence and returns the minimum resulting value.
		/// </summary>
		public static TResult Min<TSource, TResult>(
			this IEnumerable<TSource> source,
			Func<TSource, TResult> selector) {
			return source.Select(selector).Min();
		}

		/// <summary>
		/// Returns the maximum value in a generic sequence.
		/// </summary>
		public static TSource Max<TSource>(
			this IEnumerable<TSource> source) {
			var comparer = Comparer<TSource>.Default;
			return source.MinMaxImpl((x, y) => comparer.Compare(x, y) > 0);
		}

		/// <summary>
		/// Invokes a transform function on each element of a generic 
		/// sequence and returns the maximum resulting value.
		/// </summary>
		public static TResult Max<TSource, TResult>(
			this IEnumerable<TSource> source,
			Func<TSource, TResult> selector) {
			return source.Select(selector).Max();
		}

		/// <summary>
		/// Makes an enumerator seen as enumerable once more.
		/// </summary>
		/// <remarks>
		/// The supplied enumerator must have been started. The first element
		/// returned is the element the enumerator was on when passed in.
		/// DO NOT use this method if the caller must be a generator. It is
		/// mostly safe among aggregate operations.
		/// </remarks>
		private static IEnumerable<T> Renumerable<T>(this IEnumerator<T> e) {
			Debug.Assert(e != null);

			do {
				yield return e.Current;
			} while (e.MoveNext());
		}

		/// <summary>
		/// Sorts the elements of a sequence in ascending order according to a key.
		/// </summary>
		public static IOrderedEnumerable<TSource> OrderBy<TSource, TKey>(
			this IEnumerable<TSource> source,
			Func<TSource, TKey> keySelector) {
			return source.OrderBy(keySelector, /* comparer */ null);
		}

		/// <summary>
		/// Sorts the elements of a sequence in ascending order by using a 
		/// specified comparer.
		/// </summary>
		public static IOrderedEnumerable<TSource> OrderBy<TSource, TKey>(
			this IEnumerable<TSource> source,
			Func<TSource, TKey> keySelector,
			IComparer<TKey> comparer) {
			if (source == null) {
				throw new ArgumentNullException("source");
			}

			if (keySelector == null) {
				throw new ArgumentNullException("keySelector");
			}

			return new OrderedEnumerable<TSource, TKey>(source, keySelector, comparer, /* descending */ false);
		}

		/// <summary>
		/// Sorts the elements of a sequence in descending order according to a key.
		/// </summary>
		public static IOrderedEnumerable<TSource> OrderByDescending<TSource, TKey>(
			this IEnumerable<TSource> source,
			Func<TSource, TKey> keySelector) {
			return source.OrderByDescending(keySelector, /* comparer */ null);
		}

		/// <summary>
		///  Sorts the elements of a sequence in descending order by using a 
		/// specified comparer. 
		/// </summary>
		public static IOrderedEnumerable<TSource> OrderByDescending<TSource, TKey>(
			this IEnumerable<TSource> source,
			Func<TSource, TKey> keySelector,
			IComparer<TKey> comparer) {
			if (source == null) {
				throw new ArgumentNullException("source");
			}

			if (source == null) {
				throw new ArgumentNullException("keySelector");
			}

			return new OrderedEnumerable<TSource, TKey>(source, keySelector, comparer, /* descending */ true);
		}

		/// <summary>
		/// Performs a subsequent ordering of the elements in a sequence in 
		/// ascending order according to a key.
		/// </summary>
		public static IOrderedEnumerable<TSource> ThenBy<TSource, TKey>(
			this IOrderedEnumerable<TSource> source,
			Func<TSource, TKey> keySelector) {
			return source.ThenBy(keySelector, /* comparer */ null);
		}

		/// <summary>
		/// Performs a subsequent ordering of the elements in a sequence in 
		/// ascending order by using a specified comparer.
		/// </summary>
		public static IOrderedEnumerable<TSource> ThenBy<TSource, TKey>(
			this IOrderedEnumerable<TSource> source,
			Func<TSource, TKey> keySelector,
			IComparer<TKey> comparer) {
			if (source == null) {
				throw new ArgumentNullException("source");
			}

			return source.CreateOrderedEnumerable(keySelector, comparer, /* descending */ false);
		}

		/// <summary>
		/// Performs a subsequent ordering of the elements in a sequence in 
		/// descending order, according to a key.
		/// </summary>
		public static IOrderedEnumerable<TSource> ThenByDescending<TSource, TKey>(
			this IOrderedEnumerable<TSource> source,
			Func<TSource, TKey> keySelector) {
			return source.ThenByDescending(keySelector, /* comparer */ null);
		}

		/// <summary>
		/// Performs a subsequent ordering of the elements in a sequence in 
		/// descending order by using a specified comparer.
		/// </summary>
		public static IOrderedEnumerable<TSource> ThenByDescending<TSource, TKey>(
			this IOrderedEnumerable<TSource> source,
			Func<TSource, TKey> keySelector,
			IComparer<TKey> comparer) {
			if (source == null) {
				throw new ArgumentNullException("source");
			}

			return source.CreateOrderedEnumerable(keySelector, comparer, /* descending */ true);
		}

		/// <summary>
		/// Base implementation for Intersect and Except operators.
		/// </summary>
		private static IEnumerable<TSource> IntersectExceptImpl<TSource>(
			this IEnumerable<TSource> first,
			IEnumerable<TSource> second,
			IEqualityComparer<TSource> comparer,
			bool flag) {
			if (first == null) {
				throw new ArgumentNullException("first");
			}

			if (second == null) {
				throw new ArgumentNullException("second");
			}

			var keys = new List<Key<TSource>>();
			var flags = new Dictionary<Key<TSource>, bool>(new KeyComparer<TSource>(comparer));

			foreach (var item in from item in first
				select new Key<TSource>(item)
				into item
				where !flags.ContainsKey(item)
				select item) {
				flags.Add(item, !flag);
				keys.Add(item);
			}

			foreach (var item in from item in second
				select new Key<TSource>(item)
				into item
				where flags.ContainsKey(item)
				select item) {
				flags[item] = flag;
			}

			//
			// As per docs, "the marked elements are yielded in the order in 
			// which they were collected.
			//

			return from item in keys where flags[item] select item.Value;
		}

		/// <summary>
		/// Produces the set intersection of two sequences by using the 
		/// default equality comparer to compare values.
		/// </summary>
		public static IEnumerable<TSource> Intersect<TSource>(
			this IEnumerable<TSource> first,
			IEnumerable<TSource> second) {
			return first.Intersect(second, /* comparer */ null);
		}

		/// <summary>
		/// Produces the set intersection of two sequences by using the 
		/// specified <see cref="IEqualityComparer{T}" /> to compare values.
		/// </summary>
		public static IEnumerable<TSource> Intersect<TSource>(
			this IEnumerable<TSource> first,
			IEnumerable<TSource> second,
			IEqualityComparer<TSource> comparer) {
			return IntersectExceptImpl(first, second, comparer, /* flag */ true);
		}

		/// <summary>
		/// Produces the set difference of two sequences by using the 
		/// default equality comparer to compare values.
		/// </summary>
		public static IEnumerable<TSource> Except<TSource>(
			this IEnumerable<TSource> first,
			IEnumerable<TSource> second) {
			return first.Except(second, /* comparer */ null);
		}

		/// <summary>
		/// Produces the set difference of two sequences by using the 
		/// specified <see cref="IEqualityComparer{T}" /> to compare values.
		/// </summary>
		public static IEnumerable<TSource> Except<TSource>(
			this IEnumerable<TSource> first,
			IEnumerable<TSource> second,
			IEqualityComparer<TSource> comparer) {
			return IntersectExceptImpl(first, second, comparer, /* flag */ false);
		}

		/// <summary>
		/// Creates a <see cref="Dictionary{TKey,TValue}" /> from an 
		/// <see cref="IEnumerable{T}" /> according to a specified key 
		/// selector function.
		/// </summary>
		public static Dictionary<TKey, TSource> ToDictionary<TSource, TKey>(
			this IEnumerable<TSource> source,
			Func<TSource, TKey> keySelector) {
			return source.ToDictionary(keySelector, /* comparer */ null);
		}

		/// <summary>
		/// Creates a <see cref="Dictionary{TKey,TValue}" /> from an 
		/// <see cref="IEnumerable{T}" /> according to a specified key 
		/// selector function and key comparer.
		/// </summary>
		public static Dictionary<TKey, TSource> ToDictionary<TSource, TKey>(
			this IEnumerable<TSource> source,
			Func<TSource, TKey> keySelector,
			IEqualityComparer<TKey> comparer) {
			return source.ToDictionary(keySelector, e => e, comparer);
		}

		/// <summary>
		/// Creates a <see cref="Dictionary{TKey,TValue}" /> from an 
		/// <see cref="IEnumerable{T}" /> according to specified key 
		/// selector and element selector functions.
		/// </summary>
		public static Dictionary<TKey, TElement> ToDictionary<TSource, TKey, TElement>(
			this IEnumerable<TSource> source,
			Func<TSource, TKey> keySelector,
			Func<TSource, TElement> elementSelector) {
			return source.ToDictionary(keySelector, elementSelector, /* comparer */ null);
		}

		/// <summary>
		/// Creates a <see cref="Dictionary{TKey,TValue}" /> from an 
		/// <see cref="IEnumerable{T}" /> according to a specified key 
		/// selector function, a comparer, and an element selector function.
		/// </summary>
		public static Dictionary<TKey, TElement> ToDictionary<TSource, TKey, TElement>(
			this IEnumerable<TSource> source,
			Func<TSource, TKey> keySelector,
			Func<TSource, TElement> elementSelector,
			IEqualityComparer<TKey> comparer) {
			if (source == null) {
				throw new ArgumentNullException("source");
			}

			if (keySelector == null) {
				throw new ArgumentNullException("keySelector");
			}

			if (elementSelector == null) {
				throw new ArgumentNullException("elementSelector");
			}

			var dict = new Dictionary<TKey, TElement>(comparer);

			foreach (var item in source) {
				//
				// ToDictionary is meant to throw ArgumentNullException if
				// keySelector produces a key that is null and 
				// Argument exception if keySelector produces duplicate keys 
				// for two elements. Incidentally, the doucmentation for
				// IDictionary<TKey, TValue>.Add says that the Add method
				// throws the same exceptions under the same circumstances
				// so we don't need to do any additional checking or work
				// here and let the Add implementation do all the heavy
				// lifting.
				//

				dict.Add(keySelector(item), elementSelector(item));
			}

			return dict;
		}

		/// <summary>
		/// Correlates the elements of two sequences based on matching keys. 
		/// The default equality comparer is used to compare keys.
		/// </summary>
		public static IEnumerable<TResult> Join<TOuter, TInner, TKey, TResult>(
			this IEnumerable<TOuter> outer,
			IEnumerable<TInner> inner,
			Func<TOuter, TKey> outerKeySelector,
			Func<TInner, TKey> innerKeySelector,
			Func<TOuter, TInner, TResult> resultSelector) {
			return outer.Join(inner, outerKeySelector, innerKeySelector, resultSelector, /* comparer */ null);
		}

		/// <summary>
		/// Correlates the elements of two sequences based on matching keys. 
		/// The default equality comparer is used to compare keys. A 
		/// specified <see cref="IEqualityComparer{T}" /> is used to compare keys.
		/// </summary>
		public static IEnumerable<TResult> Join<TOuter, TInner, TKey, TResult>(
			this IEnumerable<TOuter> outer,
			IEnumerable<TInner> inner,
			Func<TOuter, TKey> outerKeySelector,
			Func<TInner, TKey> innerKeySelector,
			Func<TOuter, TInner, TResult> resultSelector,
			IEqualityComparer<TKey> comparer) {
			if (outer == null) {
				throw new ArgumentNullException("outer");
			}

			if (inner == null) {
				throw new ArgumentNullException("inner");
			}

			if (outerKeySelector == null) {
				throw new ArgumentNullException("outerKeySelector");
			}

			if (innerKeySelector == null) {
				throw new ArgumentNullException("innerKeySelector");
			}

			if (resultSelector == null) {
				throw new ArgumentNullException("resultSelector");
			}

			var lookup = inner.ToLookup(innerKeySelector, comparer);

			return
				from o in outer
				from i in lookup[outerKeySelector(o)]
				select resultSelector(o, i);
		}

		/// <summary>
		/// Correlates the elements of two sequences based on equality of 
		/// keys and groups the results. The default equality comparer is 
		/// used to compare keys.
		/// </summary>
		public static IEnumerable<TResult> GroupJoin<TOuter, TInner, TKey, TResult>(
			this IEnumerable<TOuter> outer,
			IEnumerable<TInner> inner,
			Func<TOuter, TKey> outerKeySelector,
			Func<TInner, TKey> innerKeySelector,
			Func<TOuter, IEnumerable<TInner>, TResult> resultSelector) {
			return outer.GroupJoin(inner, outerKeySelector, innerKeySelector, resultSelector, /* comparer */ null);
		}

		/// <summary>
		/// Correlates the elements of two sequences based on equality of 
		/// keys and groups the results. The default equality comparer is 
		/// used to compare keys. A specified <see cref="IEqualityComparer{T}" /> 
		/// is used to compare keys.
		/// </summary>
		public static IEnumerable<TResult> GroupJoin<TOuter, TInner, TKey, TResult>(
			this IEnumerable<TOuter> outer,
			IEnumerable<TInner> inner,
			Func<TOuter, TKey> outerKeySelector,
			Func<TInner, TKey> innerKeySelector,
			Func<TOuter, IEnumerable<TInner>, TResult> resultSelector,
			IEqualityComparer<TKey> comparer) {
			if (outer == null) {
				throw new ArgumentNullException("outer");
			}

			if (inner == null) {
				throw new ArgumentNullException("inner");
			}

			if (outerKeySelector == null) {
				throw new ArgumentNullException("outerKeySelector");
			}

			if (innerKeySelector == null) {
				throw new ArgumentNullException("innerKeySelector");
			}

			if (resultSelector == null) {
				throw new ArgumentNullException("resultSelector");
			}

			var lookup = inner.ToLookup(innerKeySelector, comparer);
			return outer.Select(o => resultSelector(o, lookup[outerKeySelector(o)]));
		}

		private static class Sequence<T> {
			public static readonly IEnumerable<T> Empty = new T[0];
		}

		private sealed class Grouping<K, V> : List<V>, IGrouping<K, V> {
			internal Grouping(K key) {
				Key = key;
			}

			public K Key { get; private set; }
		}
	}
}

// $Id: Enumerable.g.tt 71137f497bf2 2012/04/16 20:01:27 azizatif $

namespace System.Linq {
	#region Imports

	using System;
	using Collections.Generic;

	#endregion

	// This partial implementation was template-generated:
	// Mon, 16 Apr 2012 20:05:53 GMT

	internal partial class Enumerable {
		/// <summary>
		/// Computes the sum of a sequence of nullable <see cref="System.Int32" /> values.
		/// </summary>
		public static int Sum(
			this IEnumerable<int> source) {
			if (source == null) {
				throw new ArgumentNullException("source");
			}

			var sum = 0;
			foreach (var num in source) {
				sum = checked(sum + num);
			}

			return sum;
		}

		/// <summary>
		/// Computes the sum of a sequence of nullable <see cref="System.Int32" /> 
		/// values that are obtained by invoking a transform function on 
		/// each element of the input sequence.
		/// </summary>
		public static int Sum<TSource>(
			this IEnumerable<TSource> source,
			Func<TSource, int> selector) {
			return source.Select(selector).Sum();
		}

		/// <summary>
		/// Computes the average of a sequence of nullable <see cref="System.Int32" /> values.
		/// </summary>
		public static double Average(
			this IEnumerable<int> source) {
			if (source == null) {
				throw new ArgumentNullException("source");
			}

			long sum = 0;
			long count = 0;

			foreach (var num in source) {
				checked {
					sum += (int) num;
					count++;
				}
			}

			if (count == 0) {
				throw new InvalidOperationException();
			}

			return (double) sum / count;
		}

		/// <summary>
		/// Computes the average of a sequence of nullable <see cref="System.Int32" /> values 
		/// that are obtained by invoking a transform function on each 
		/// element of the input sequence.
		/// </summary>
		public static double Average<TSource>(
			this IEnumerable<TSource> source,
			Func<TSource, int> selector) {
			return source.Select(selector).Average();
		}


		/// <summary>
		/// Computes the sum of a sequence of <see cref="System.Int32" /> values.
		/// </summary>
		public static int? Sum(
			this IEnumerable<int?> source) {
			if (source == null) {
				throw new ArgumentNullException("source");
			}

			var sum = 0;
			foreach (var num in source) {
				sum = checked(sum + (num ?? 0));
			}

			return sum;
		}

		/// <summary>
		/// Computes the sum of a sequence of <see cref="System.Int32" /> 
		/// values that are obtained by invoking a transform function on 
		/// each element of the input sequence.
		/// </summary>
		public static int? Sum<TSource>(
			this IEnumerable<TSource> source,
			Func<TSource, int?> selector) {
			return source.Select(selector).Sum();
		}

		/// <summary>
		/// Computes the average of a sequence of <see cref="System.Int32" /> values.
		/// </summary>
		public static double? Average(
			this IEnumerable<int?> source) {
			if (source == null) {
				throw new ArgumentNullException("source");
			}

			long sum = 0;
			long count = 0;

			foreach (var num in source.Where(n => n != null)) {
				checked {
					sum += (int) num;
					count++;
				}
			}

			if (count == 0) {
				return null;
			}

			return (double?) sum / count;
		}

		/// <summary>
		/// Computes the average of a sequence of <see cref="System.Int32" /> values 
		/// that are obtained by invoking a transform function on each 
		/// element of the input sequence.
		/// </summary>
		public static double? Average<TSource>(
			this IEnumerable<TSource> source,
			Func<TSource, int?> selector) {
			return source.Select(selector).Average();
		}

		/// <summary>
		/// Returns the minimum value in a sequence of nullable 
		/// <see cref="System.Int32" /> values.
		/// </summary>
		public static int? Min(
			this IEnumerable<int?> source) {
			if (source == null) {
				throw new ArgumentNullException("source");
			}

			return MinMaxImpl(source.Where(x => x != null), null, (min, x) => min < x);
		}

		/// <summary>
		/// Invokes a transform function on each element of a sequence and 
		/// returns the minimum nullable <see cref="System.Int32" /> value.
		/// </summary>
		public static int? Min<TSource>(
			this IEnumerable<TSource> source,
			Func<TSource, int?> selector) {
			return source.Select(selector).Min();
		}

		/// <summary>
		/// Returns the maximum value in a sequence of nullable 
		/// <see cref="System.Int32" /> values.
		/// </summary>
		public static int? Max(
			this IEnumerable<int?> source) {
			if (source == null) {
				throw new ArgumentNullException("source");
			}

			return MinMaxImpl(source.Where(x => x != null),
				null, (max, x) => x == null || max != null && x.Value < max.Value);
		}

		/// <summary>
		/// Invokes a transform function on each element of a sequence and 
		/// returns the maximum nullable <see cref="System.Int32" /> value.
		/// </summary>
		public static int? Max<TSource>(
			this IEnumerable<TSource> source,
			Func<TSource, int?> selector) {
			return source.Select(selector).Max();
		}

		/// <summary>
		/// Computes the sum of a sequence of nullable <see cref="System.Int64" /> values.
		/// </summary>
		public static long Sum(
			this IEnumerable<long> source) {
			if (source == null) {
				throw new ArgumentNullException("source");
			}

			long sum = 0;
			foreach (var num in source) {
				sum = checked(sum + num);
			}

			return sum;
		}

		/// <summary>
		/// Computes the sum of a sequence of nullable <see cref="System.Int64" /> 
		/// values that are obtained by invoking a transform function on 
		/// each element of the input sequence.
		/// </summary>
		public static long Sum<TSource>(
			this IEnumerable<TSource> source,
			Func<TSource, long> selector) {
			return source.Select(selector).Sum();
		}

		/// <summary>
		/// Computes the average of a sequence of nullable <see cref="System.Int64" /> values.
		/// </summary>
		public static double Average(
			this IEnumerable<long> source) {
			if (source == null) {
				throw new ArgumentNullException("source");
			}

			long sum = 0;
			long count = 0;

			foreach (var num in source) {
				checked {
					sum += (long) num;
					count++;
				}
			}

			if (count == 0) {
				throw new InvalidOperationException();
			}

			return (double) sum / count;
		}

		/// <summary>
		/// Computes the average of a sequence of nullable <see cref="System.Int64" /> values 
		/// that are obtained by invoking a transform function on each 
		/// element of the input sequence.
		/// </summary>
		public static double Average<TSource>(
			this IEnumerable<TSource> source,
			Func<TSource, long> selector) {
			return source.Select(selector).Average();
		}


		/// <summary>
		/// Computes the sum of a sequence of <see cref="System.Int64" /> values.
		/// </summary>
		public static long? Sum(
			this IEnumerable<long?> source) {
			if (source == null) {
				throw new ArgumentNullException("source");
			}

			long sum = 0;
			foreach (var num in source) {
				sum = checked(sum + (num ?? 0));
			}

			return sum;
		}

		/// <summary>
		/// Computes the sum of a sequence of <see cref="System.Int64" /> 
		/// values that are obtained by invoking a transform function on 
		/// each element of the input sequence.
		/// </summary>
		public static long? Sum<TSource>(
			this IEnumerable<TSource> source,
			Func<TSource, long?> selector) {
			return source.Select(selector).Sum();
		}

		/// <summary>
		/// Computes the average of a sequence of <see cref="System.Int64" /> values.
		/// </summary>
		public static double? Average(
			this IEnumerable<long?> source) {
			if (source == null) {
				throw new ArgumentNullException("source");
			}

			long sum = 0;
			long count = 0;

			foreach (var num in source.Where(n => n != null)) {
				checked {
					sum += (long) num;
					count++;
				}
			}

			if (count == 0) {
				return null;
			}

			return (double?) sum / count;
		}

		/// <summary>
		/// Computes the average of a sequence of <see cref="System.Int64" /> values 
		/// that are obtained by invoking a transform function on each 
		/// element of the input sequence.
		/// </summary>
		public static double? Average<TSource>(
			this IEnumerable<TSource> source,
			Func<TSource, long?> selector) {
			return source.Select(selector).Average();
		}

		/// <summary>
		/// Returns the minimum value in a sequence of nullable 
		/// <see cref="System.Int64" /> values.
		/// </summary>
		public static long? Min(
			this IEnumerable<long?> source) {
			if (source == null) {
				throw new ArgumentNullException("source");
			}

			return MinMaxImpl(source.Where(x => x != null), null, (min, x) => min < x);
		}

		/// <summary>
		/// Invokes a transform function on each element of a sequence and 
		/// returns the minimum nullable <see cref="System.Int64" /> value.
		/// </summary>
		public static long? Min<TSource>(
			this IEnumerable<TSource> source,
			Func<TSource, long?> selector) {
			return source.Select(selector).Min();
		}

		/// <summary>
		/// Returns the maximum value in a sequence of nullable 
		/// <see cref="System.Int64" /> values.
		/// </summary>
		public static long? Max(
			this IEnumerable<long?> source) {
			if (source == null) {
				throw new ArgumentNullException("source");
			}

			return MinMaxImpl(source.Where(x => x != null),
				null, (max, x) => x == null || max != null && x.Value < max.Value);
		}

		/// <summary>
		/// Invokes a transform function on each element of a sequence and 
		/// returns the maximum nullable <see cref="System.Int64" /> value.
		/// </summary>
		public static long? Max<TSource>(
			this IEnumerable<TSource> source,
			Func<TSource, long?> selector) {
			return source.Select(selector).Max();
		}

		/// <summary>
		/// Computes the sum of a sequence of nullable <see cref="System.Single" /> values.
		/// </summary>
		public static float Sum(
			this IEnumerable<float> source) {
			if (source == null) {
				throw new ArgumentNullException("source");
			}

			float sum = 0;
			foreach (var num in source) {
				sum = checked(sum + num);
			}

			return sum;
		}

		/// <summary>
		/// Computes the sum of a sequence of nullable <see cref="System.Single" /> 
		/// values that are obtained by invoking a transform function on 
		/// each element of the input sequence.
		/// </summary>
		public static float Sum<TSource>(
			this IEnumerable<TSource> source,
			Func<TSource, float> selector) {
			return source.Select(selector).Sum();
		}

		/// <summary>
		/// Computes the average of a sequence of nullable <see cref="System.Single" /> values.
		/// </summary>
		public static float Average(
			this IEnumerable<float> source) {
			if (source == null) {
				throw new ArgumentNullException("source");
			}

			float sum = 0;
			long count = 0;

			foreach (var num in source) {
				checked {
					sum += (float) num;
					count++;
				}
			}

			if (count == 0) {
				throw new InvalidOperationException();
			}

			return (float) sum / count;
		}

		/// <summary>
		/// Computes the average of a sequence of nullable <see cref="System.Single" /> values 
		/// that are obtained by invoking a transform function on each 
		/// element of the input sequence.
		/// </summary>
		public static float Average<TSource>(
			this IEnumerable<TSource> source,
			Func<TSource, float> selector) {
			return source.Select(selector).Average();
		}


		/// <summary>
		/// Computes the sum of a sequence of <see cref="System.Single" /> values.
		/// </summary>
		public static float? Sum(
			this IEnumerable<float?> source) {
			if (source == null) {
				throw new ArgumentNullException("source");
			}

			float sum = 0;
			foreach (var num in source) {
				sum = checked(sum + (num ?? 0));
			}

			return sum;
		}

		/// <summary>
		/// Computes the sum of a sequence of <see cref="System.Single" /> 
		/// values that are obtained by invoking a transform function on 
		/// each element of the input sequence.
		/// </summary>
		public static float? Sum<TSource>(
			this IEnumerable<TSource> source,
			Func<TSource, float?> selector) {
			return source.Select(selector).Sum();
		}

		/// <summary>
		/// Computes the average of a sequence of <see cref="System.Single" /> values.
		/// </summary>
		public static float? Average(
			this IEnumerable<float?> source) {
			if (source == null) {
				throw new ArgumentNullException("source");
			}

			float sum = 0;
			long count = 0;

			foreach (var num in source.Where(n => n != null)) {
				checked {
					sum += (float) num;
					count++;
				}
			}

			if (count == 0) {
				return null;
			}

			return (float?) sum / count;
		}

		/// <summary>
		/// Computes the average of a sequence of <see cref="System.Single" /> values 
		/// that are obtained by invoking a transform function on each 
		/// element of the input sequence.
		/// </summary>
		public static float? Average<TSource>(
			this IEnumerable<TSource> source,
			Func<TSource, float?> selector) {
			return source.Select(selector).Average();
		}

		/// <summary>
		/// Returns the minimum value in a sequence of nullable 
		/// <see cref="System.Single" /> values.
		/// </summary>
		public static float? Min(
			this IEnumerable<float?> source) {
			if (source == null) {
				throw new ArgumentNullException("source");
			}

			return MinMaxImpl(source.Where(x => x != null), null, (min, x) => min < x);
		}

		/// <summary>
		/// Invokes a transform function on each element of a sequence and 
		/// returns the minimum nullable <see cref="System.Single" /> value.
		/// </summary>
		public static float? Min<TSource>(
			this IEnumerable<TSource> source,
			Func<TSource, float?> selector) {
			return source.Select(selector).Min();
		}

		/// <summary>
		/// Returns the maximum value in a sequence of nullable 
		/// <see cref="System.Single" /> values.
		/// </summary>
		public static float? Max(
			this IEnumerable<float?> source) {
			if (source == null) {
				throw new ArgumentNullException("source");
			}

			return MinMaxImpl(source.Where(x => x != null),
				null, (max, x) => x == null || max != null && x.Value < max.Value);
		}

		/// <summary>
		/// Invokes a transform function on each element of a sequence and 
		/// returns the maximum nullable <see cref="System.Single" /> value.
		/// </summary>
		public static float? Max<TSource>(
			this IEnumerable<TSource> source,
			Func<TSource, float?> selector) {
			return source.Select(selector).Max();
		}

		/// <summary>
		/// Computes the sum of a sequence of nullable <see cref="System.Double" /> values.
		/// </summary>
		public static double Sum(
			this IEnumerable<double> source) {
			if (source == null) {
				throw new ArgumentNullException("source");
			}

			double sum = 0;
			foreach (var num in source) {
				sum = checked(sum + num);
			}

			return sum;
		}

		/// <summary>
		/// Computes the sum of a sequence of nullable <see cref="System.Double" /> 
		/// values that are obtained by invoking a transform function on 
		/// each element of the input sequence.
		/// </summary>
		public static double Sum<TSource>(
			this IEnumerable<TSource> source,
			Func<TSource, double> selector) {
			return source.Select(selector).Sum();
		}

		/// <summary>
		/// Computes the average of a sequence of nullable <see cref="System.Double" /> values.
		/// </summary>
		public static double Average(
			this IEnumerable<double> source) {
			if (source == null) {
				throw new ArgumentNullException("source");
			}

			double sum = 0;
			long count = 0;

			foreach (var num in source) {
				checked {
					sum += (double) num;
					count++;
				}
			}

			if (count == 0) {
				throw new InvalidOperationException();
			}

			return (double) sum / count;
		}

		/// <summary>
		/// Computes the average of a sequence of nullable <see cref="System.Double" /> values 
		/// that are obtained by invoking a transform function on each 
		/// element of the input sequence.
		/// </summary>
		public static double Average<TSource>(
			this IEnumerable<TSource> source,
			Func<TSource, double> selector) {
			return source.Select(selector).Average();
		}


		/// <summary>
		/// Computes the sum of a sequence of <see cref="System.Double" /> values.
		/// </summary>
		public static double? Sum(
			this IEnumerable<double?> source) {
			if (source == null) {
				throw new ArgumentNullException("source");
			}

			double sum = 0;
			foreach (var num in source) {
				sum = checked(sum + (num ?? 0));
			}

			return sum;
		}

		/// <summary>
		/// Computes the sum of a sequence of <see cref="System.Double" /> 
		/// values that are obtained by invoking a transform function on 
		/// each element of the input sequence.
		/// </summary>
		public static double? Sum<TSource>(
			this IEnumerable<TSource> source,
			Func<TSource, double?> selector) {
			return source.Select(selector).Sum();
		}

		/// <summary>
		/// Computes the average of a sequence of <see cref="System.Double" /> values.
		/// </summary>
		public static double? Average(
			this IEnumerable<double?> source) {
			if (source == null) {
				throw new ArgumentNullException("source");
			}

			double sum = 0;
			long count = 0;

			foreach (var num in source.Where(n => n != null)) {
				checked {
					sum += (double) num;
					count++;
				}
			}

			if (count == 0) {
				return null;
			}

			return (double?) sum / count;
		}

		/// <summary>
		/// Computes the average of a sequence of <see cref="System.Double" /> values 
		/// that are obtained by invoking a transform function on each 
		/// element of the input sequence.
		/// </summary>
		public static double? Average<TSource>(
			this IEnumerable<TSource> source,
			Func<TSource, double?> selector) {
			return source.Select(selector).Average();
		}

		/// <summary>
		/// Returns the minimum value in a sequence of nullable 
		/// <see cref="System.Double" /> values.
		/// </summary>
		public static double? Min(
			this IEnumerable<double?> source) {
			if (source == null) {
				throw new ArgumentNullException("source");
			}

			return MinMaxImpl(source.Where(x => x != null), null, (min, x) => min < x);
		}

		/// <summary>
		/// Invokes a transform function on each element of a sequence and 
		/// returns the minimum nullable <see cref="System.Double" /> value.
		/// </summary>
		public static double? Min<TSource>(
			this IEnumerable<TSource> source,
			Func<TSource, double?> selector) {
			return source.Select(selector).Min();
		}

		/// <summary>
		/// Returns the maximum value in a sequence of nullable 
		/// <see cref="System.Double" /> values.
		/// </summary>
		public static double? Max(
			this IEnumerable<double?> source) {
			if (source == null) {
				throw new ArgumentNullException("source");
			}

			return MinMaxImpl(source.Where(x => x != null),
				null, (max, x) => x == null || max != null && x.Value < max.Value);
		}

		/// <summary>
		/// Invokes a transform function on each element of a sequence and 
		/// returns the maximum nullable <see cref="System.Double" /> value.
		/// </summary>
		public static double? Max<TSource>(
			this IEnumerable<TSource> source,
			Func<TSource, double?> selector) {
			return source.Select(selector).Max();
		}

		/// <summary>
		/// Computes the sum of a sequence of nullable <see cref="System.Decimal" /> values.
		/// </summary>
		public static decimal Sum(
			this IEnumerable<decimal> source) {
			if (source == null) {
				throw new ArgumentNullException("source");
			}

			decimal sum = 0;
			foreach (var num in source) {
				sum = checked(sum + num);
			}

			return sum;
		}

		/// <summary>
		/// Computes the sum of a sequence of nullable <see cref="System.Decimal" /> 
		/// values that are obtained by invoking a transform function on 
		/// each element of the input sequence.
		/// </summary>
		public static decimal Sum<TSource>(
			this IEnumerable<TSource> source,
			Func<TSource, decimal> selector) {
			return source.Select(selector).Sum();
		}

		/// <summary>
		/// Computes the average of a sequence of nullable <see cref="System.Decimal" /> values.
		/// </summary>
		public static decimal Average(
			this IEnumerable<decimal> source) {
			if (source == null) {
				throw new ArgumentNullException("source");
			}

			decimal sum = 0;
			long count = 0;

			foreach (var num in source) {
				checked {
					sum += (decimal) num;
					count++;
				}
			}

			if (count == 0) {
				throw new InvalidOperationException();
			}

			return (decimal) sum / count;
		}

		/// <summary>
		/// Computes the average of a sequence of nullable <see cref="System.Decimal" /> values 
		/// that are obtained by invoking a transform function on each 
		/// element of the input sequence.
		/// </summary>
		public static decimal Average<TSource>(
			this IEnumerable<TSource> source,
			Func<TSource, decimal> selector) {
			return source.Select(selector).Average();
		}


		/// <summary>
		/// Computes the sum of a sequence of <see cref="System.Decimal" /> values.
		/// </summary>
		public static decimal? Sum(
			this IEnumerable<decimal?> source) {
			if (source == null) {
				throw new ArgumentNullException("source");
			}

			decimal sum = 0;
			foreach (var num in source) {
				sum = checked(sum + (num ?? 0));
			}

			return sum;
		}

		/// <summary>
		/// Computes the sum of a sequence of <see cref="System.Decimal" /> 
		/// values that are obtained by invoking a transform function on 
		/// each element of the input sequence.
		/// </summary>
		public static decimal? Sum<TSource>(
			this IEnumerable<TSource> source,
			Func<TSource, decimal?> selector) {
			return source.Select(selector).Sum();
		}

		/// <summary>
		/// Computes the average of a sequence of <see cref="System.Decimal" /> values.
		/// </summary>
		public static decimal? Average(
			this IEnumerable<decimal?> source) {
			if (source == null) {
				throw new ArgumentNullException("source");
			}

			decimal sum = 0;
			long count = 0;

			foreach (var num in source.Where(n => n != null)) {
				checked {
					sum += (decimal) num;
					count++;
				}
			}

			if (count == 0) {
				return null;
			}

			return (decimal?) sum / count;
		}

		/// <summary>
		/// Computes the average of a sequence of <see cref="System.Decimal" /> values 
		/// that are obtained by invoking a transform function on each 
		/// element of the input sequence.
		/// </summary>
		public static decimal? Average<TSource>(
			this IEnumerable<TSource> source,
			Func<TSource, decimal?> selector) {
			return source.Select(selector).Average();
		}

		/// <summary>
		/// Returns the minimum value in a sequence of nullable 
		/// <see cref="System.Decimal" /> values.
		/// </summary>
		public static decimal? Min(
			this IEnumerable<decimal?> source) {
			if (source == null) {
				throw new ArgumentNullException("source");
			}

			return MinMaxImpl(source.Where(x => x != null), null, (min, x) => min < x);
		}

		/// <summary>
		/// Invokes a transform function on each element of a sequence and 
		/// returns the minimum nullable <see cref="System.Decimal" /> value.
		/// </summary>
		public static decimal? Min<TSource>(
			this IEnumerable<TSource> source,
			Func<TSource, decimal?> selector) {
			return source.Select(selector).Min();
		}

		/// <summary>
		/// Returns the maximum value in a sequence of nullable 
		/// <see cref="System.Decimal" /> values.
		/// </summary>
		public static decimal? Max(
			this IEnumerable<decimal?> source) {
			if (source == null) {
				throw new ArgumentNullException("source");
			}

			return MinMaxImpl(source.Where(x => x != null),
				null, (max, x) => x == null || max != null && x.Value < max.Value);
		}

		/// <summary>
		/// Invokes a transform function on each element of a sequence and 
		/// returns the maximum nullable <see cref="System.Decimal" /> value.
		/// </summary>
		public static decimal? Max<TSource>(
			this IEnumerable<TSource> source,
			Func<TSource, decimal?> selector) {
			return source.Select(selector).Max();
		}
	}
}

// $Id: Func.cs 71137f497bf2 2012/04/16 20:01:27 azizatif $

namespace System {
#if LINQBRIDGE_LIB
	public delegate TResult Func<out TResult>();

	public delegate TResult Func<in T, out TResult>(T a);

	public delegate TResult Func<in T1, in T2, out TResult>(T1 arg1, T2 arg2);

	public delegate TResult Func<in T1, in T2, in T3, out TResult>(T1 arg1, T2 arg2, T3 arg3);

	public delegate TResult Func<in T1, in T2, in T3, in T4, out TResult>(T1 arg1, T2 arg2, T3 arg3, T4 arg4);

#else
	internal delegate TResult Func<TResult>();

	internal delegate TResult Func<T, TResult>(T a);

	internal delegate TResult Func<T1, T2, TResult>(T1 arg1, T2 arg2);

	internal delegate TResult Func<T1, T2, T3, TResult>(T1 arg1, T2 arg2, T3 arg3);

	internal delegate TResult Func<T1, T2, T3, T4, TResult>(T1 arg1, T2 arg2, T3 arg3, T4 arg4);

#endif
}

// $Id: IGrouping.cs 71137f497bf2 2012/04/16 20:01:27 azizatif $

namespace System.Linq {
	#region Imports

	using Collections.Generic;

	#endregion

	/// <summary>
	/// Represents a collection of objects that have a common key.
	/// </summary>
	internal partial interface IGrouping<out TKey, TElement> : IEnumerable<TElement> {
		/// <summary>
		/// Gets the key of the <see cref="IGrouping{TKey,TElement}" />.
		/// </summary>

		TKey Key { get; }
	}
}

// $Id: ILookup.cs 71137f497bf2 2012/04/16 20:01:27 azizatif $

namespace System.Linq {
	using Collections.Generic;

	/// <summary>
	/// Defines an indexer, size property, and Boolean search method for 
	/// data structures that map keys to <see cref="IEnumerable{T}"/> 
	/// sequences of values.
	/// </summary>
	internal partial interface ILookup<TKey, TElement> : IEnumerable<IGrouping<TKey, TElement>> {
		bool Contains(TKey key);
		int Count { get; }
		IEnumerable<TElement> this[TKey key] { get; }
	}
}

// $Id: Internal.cs 1567e00f1a20 2012/04/17 16:09:51 azizatif $

namespace LinqBridge {
	#region Imports

	using System;
	using System.Collections.Generic;

	#endregion

	/// <remarks>
	/// This type is not intended to be used directly from user code.
	/// It may be removed or changed in a future version without notice.
	/// </remarks>
	internal sealed class DelegatingComparer<T> : IComparer<T> {
		private readonly Func<T, T, int> _comparer;

		public DelegatingComparer(Func<T, T, int> comparer) {
			if (comparer == null) {
				throw new ArgumentNullException("comparer");
			}

			_comparer = comparer;
		}

		public int Compare(T x, T y) {
			return _comparer(x, y);
		}
	}

	/// <remarks>
	/// This type is not intended to be used directly from user code.
	/// It may be removed or changed in a future version without notice.
	/// </remarks>
	internal struct Key<T> {
		public Key(T value) : this() {
			Value = value;
		}

		public T Value { get; private set; }
	}

	/// <remarks>
	/// This type is not intended to be used directly from user code.
	/// It may be removed or changed in a future version without notice.
	/// </remarks>
	internal sealed class KeyComparer<T> : IEqualityComparer<Key<T>> {
		private readonly IEqualityComparer<T> _innerComparer;

		public KeyComparer(IEqualityComparer<T> innerComparer) {
			_innerComparer = innerComparer ?? EqualityComparer<T>.Default;
		}

		public bool Equals(Key<T> x, Key<T> y) {
			return _innerComparer.Equals(x.Value, y.Value);
		}

		public int GetHashCode(Key<T> obj) {
			return obj.Value == null ? 0 : _innerComparer.GetHashCode(obj.Value);
		}
	}
}

// $Id: IOrderedEnumerable.cs 71137f497bf2 2012/04/16 20:01:27 azizatif $

namespace System.Linq {
	using Collections.Generic;

	/// <summary>
	/// Represents a sorted sequence.
	/// </summary>
	internal partial interface IOrderedEnumerable<TElement> : IEnumerable<TElement> {
		/// <summary>
		/// Performs a subsequent ordering on the elements of an 
		/// <see cref="IOrderedEnumerable{T}"/> according to a key.
		/// </summary>
		IOrderedEnumerable<TElement> CreateOrderedEnumerable<TKey>(
			Func<TElement, TKey> keySelector, IComparer<TKey> comparer, bool descending);
	}
}

// $Id: Lookup.cs c08984d432b1 2012/04/17 16:05:19 azizatif $

namespace System.Linq {
	#region Imports

	using System;
	using Collections;
	using Collections.Generic;
	using IEnumerable = Collections.IEnumerable;
	using LinqBridge;

	#endregion

	/// <summary>
	/// Represents a collection of keys each mapped to one or more values.
	/// </summary>
	internal sealed class Lookup<TKey, TElement> : ILookup<TKey, TElement> {
		private readonly Dictionary<Key<TKey>, IGrouping<TKey, TElement>> _map;
		private readonly List<Key<TKey>> _orderedKeys; // remember order of insertion

		internal Lookup(IEqualityComparer<TKey> comparer) {
			_map = new Dictionary<Key<TKey>, IGrouping<TKey, TElement>>(new KeyComparer<TKey>(comparer));
			_orderedKeys = new List<Key<TKey>>();
		}

		internal void Add(IGrouping<TKey, TElement> item) {
			var key = new Key<TKey>(item.Key);
			_map.Add(key, item);
			_orderedKeys.Add(key);
		}

		internal IEnumerable<TElement> Find(TKey key) {
			IGrouping<TKey, TElement> grouping;
			return _map.TryGetValue(new Key<TKey>(key), out grouping) ? grouping : null;
		}

		/// <summary>
		/// Gets the number of key/value collection pairs in the <see cref="Lookup{TKey,TElement}" />.
		/// </summary>

		public int Count => _map.Count;

		/// <summary>
		/// Gets the collection of values indexed by the specified key.
		/// </summary>

		public IEnumerable<TElement> this[TKey key] {
			get {
				IGrouping<TKey, TElement> result;
				return _map.TryGetValue(new Key<TKey>(key), out result) ? result : Enumerable.Empty<TElement>();
			}
		}

		/// <summary>
		/// Determines whether a specified key is in the <see cref="Lookup{TKey,TElement}" />.
		/// </summary>
		public bool Contains(TKey key) {
			return _map.ContainsKey(new Key<TKey>(key));
		}

		/// <summary>
		/// Applies a transform function to each key and its associated 
		/// values and returns the results.
		/// </summary>
		public IEnumerable<TResult> ApplyResultSelector<TResult>(
			Func<TKey, IEnumerable<TElement>, TResult> resultSelector) {
			if (resultSelector == null) {
				throw new ArgumentNullException("resultSelector");
			}

			foreach (var pair in _map) {
				yield return resultSelector(pair.Key.Value, pair.Value);
			}
		}

		/// <summary>
		/// Returns a generic enumerator that iterates through the <see cref="Lookup{TKey,TElement}" />.
		/// </summary>
		public IEnumerator<IGrouping<TKey, TElement>> GetEnumerator() {
			foreach (var key in _orderedKeys) {
				yield return _map[key];
			}
		}

		IEnumerator IEnumerable.GetEnumerator() {
			return GetEnumerator();
		}
	}
}

// $Id: OrderedEnumerable.cs 71137f497bf2 2012/04/16 20:01:27 azizatif $

namespace LinqBridge {
	#region Imports

	using System;
	using System.Collections;
	using System.Collections.Generic;
	using System.Diagnostics;
	using System.Linq;

	#endregion

	internal sealed class OrderedEnumerable<T, K> : IOrderedEnumerable<T> {
		private readonly IEnumerable<T> _source;
		private readonly Func<T[], IComparer<int>, IComparer<int>> _comparerComposer;

		public OrderedEnumerable(IEnumerable<T> source,
			Func<T, K> keySelector, IComparer<K> comparer, bool descending) :
			this(source, (_, next) => next, keySelector, comparer, descending) {
		}

		private OrderedEnumerable(IEnumerable<T> source,
			Func<T[], IComparer<int>, IComparer<int>> parent,
			Func<T, K> keySelector, IComparer<K> comparer, bool descending) {
			if (source == null) {
				throw new ArgumentNullException("source");
			}

			if (keySelector == null) {
				throw new ArgumentNullException("keySelector");
			}

			Debug.Assert(parent != null);

			_source = source;

			comparer = comparer ?? Comparer<K>.Default;
			var direction = descending ? -1 : 1;

			_comparerComposer = (items, next) => {
				Debug.Assert(items != null);
				Debug.Assert(next != null);

				var keys = new K[items.Length];
				for (var i = 0; i < items.Length; i++) {
					keys[i] = keySelector(items[i]);
				}

				return parent(items, new DelegatingComparer<int>((i, j) => {
					var result = direction * comparer.Compare(keys[i], keys[j]);
					return result != 0 ? result : next.Compare(i, j);
				}));
			};
		}

		public IOrderedEnumerable<T> CreateOrderedEnumerable<KK>(
			Func<T, KK> keySelector, IComparer<KK> comparer, bool descending) {
			return new OrderedEnumerable<T, KK>(_source, _comparerComposer, keySelector, comparer, descending);
		}

		public IEnumerator<T> GetEnumerator() {
			//
			// Sort using Array.Sort but docs say that it performs an 
			// unstable sort. LINQ, on the other hand, says OrderBy performs 
			// a stable sort. Use the item position then as a tie 
			// breaker when all keys compare equal, thus making the sort 
			// stable.
			//

			var items = _source.ToArray();
			var positionComparer = new DelegatingComparer<int>((i, j) => i.CompareTo(j));
			var comparer = _comparerComposer(items, positionComparer);
			var keys = new int[items.Length];
			for (var i = 0; i < keys.Length; i++) {
				keys[i] = i;
			}

			Array.Sort(keys, items, comparer);
			return ((IEnumerable<T>) items).GetEnumerator();
		}

		IEnumerator IEnumerable.GetEnumerator() {
			return GetEnumerator();
		}
	}
}

// $Id: Action.cs 71137f497bf2 2012/04/16 20:01:27 azizatif $

namespace System {
#if LINQBRIDGE_LIB
	public delegate void Action();

	public delegate void Action<in T1, in T2>(T1 arg1, T2 arg2);

	public delegate void Action<in T1, in T2, in T3>(T1 arg1, T2 arg2, T3 arg3);

	public delegate void Action<in T1, in T2, in T3, in T4>(T1 arg1, T2 arg2, T3 arg3, T4 arg4);

#else
	internal delegate void Action();

	internal delegate void Action<T1, T2>(T1 arg1, T2 arg2);

	internal delegate void Action<T1, T2, T3>(T1 arg1, T2 arg2, T3 arg3);

	internal delegate void Action<T1, T2, T3, T4>(T1 arg1, T2 arg2, T3 arg3, T4 arg4);

#endif
}

#endif

#endregion